#include "chatclient.h"
#include <QMutex>

extern std::map<std::string, std::vector<std::string> >global_ip2msg;
extern QMutex global_ip2msg_mutex;
extern std::map<std::string, std::map<std::string, std::vector<std::string> > >global_multi_ip2msg;
extern QMutex global_multi_ip2msg_mutex;

ChatClient::ChatClient()
{
    server_ip_ = SERVER_IP;
    server_port_ = SERVER_PORT;
    conn_socket_ = INVALID_SOCKET;
    FD_ZERO(&read_socket_set_);
    max_fd_ = -1;
}

ChatClient::~ChatClient() {
    close(conn_socket_);
    close(pipe_read_);
    close(pipe_write_);
}

int ChatClient::createPipe() {
    int pipe_fd[2];

    if (pipe(pipe_fd)) {
        return -1;
    }
    pipe_read_ = pipe_fd[0];
    pipe_write_ = pipe_fd[1];
    int options;
    for (int i = 0; i < 2; ++i) {
        if ((options = fcntl(pipe_fd[i], F_GETFL)) == -1) {
            return -1;
        }
        if (fcntl(pipe_fd[i], F_SETFL, options | O_NONBLOCK) == -1) {
            return -1;
        }
    }
    FD_SET(pipe_read_, &read_socket_set_);
    return 0;
}

int ChatClient::createSocket() {
    struct sockaddr_in server_addr;
    bzero(&server_addr, sizeof(server_addr));
    if ((conn_socket_ = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
        std::cout << "initial socket failed" << std::endl;
    }
    server_addr.sin_family = AF_INET;
    server_addr.sin_port = htons(server_port_);
    inet_pton(AF_INET, server_ip_.c_str(), &server_addr.sin_addr);

    if (connect(conn_socket_, (struct sockaddr *) &server_addr, sizeof(server_addr)) < 0) {
        std::cout << "connect failed..." << std::endl;
        std::cout << errno << std::endl;
        return -1;
    }
    int options;
    if ((options = fcntl(conn_socket_, F_GETFL)) == -1) {
        return -1;
    }
    if (fcntl(conn_socket_, F_SETFL, options | O_NONBLOCK) == -1) {
        return -1;
    }

    FD_SET(conn_socket_, &read_socket_set_);
    return 0;
}

void ChatClient::sendMsgSlots(std::string ip, std::string msg) {
    Json::FastWriter wr;
    Json::Value send_msg_json;
    send_msg_json["type"] = "m00";
    send_msg_json["ip"] = ip;
    send_msg_json["msg"] = msg;
    send_msg_  = wr.write(send_msg_json);
    write(pipe_write_, "send", 5);

}

void ChatClient::sendSynSlots() {
    Json::FastWriter wr;
    Json::Value send_msg_json;
    send_msg_json["type"] = "m01";
    send_msg_ = wr.write(send_msg_json);
    write(pipe_write_, "send", 5);
}

void ChatClient::sendMultiMsgSlots(std::string multi_ip, std::string msg) {
    Json::FastWriter wr;
    Json::Value send_msg_json;
    send_msg_json["type"] = "m04";
    send_msg_json["msg"] = msg;
    send_msg_json["multi_ip_addr"] = multi_ip;
    send_msg_ = wr.write(send_msg_json);
    write(pipe_write_, "send", 5);
}

void ChatClient::sendJoinMultiSlots(std::string multi_ip) {
    Json::FastWriter wr;
    Json::Value send_msg_json;
    send_msg_json["type"] = "m02";
    send_msg_json["multi_ip_addr"] = multi_ip;
    send_msg_ = wr.write(send_msg_json);
    write(pipe_write_, "join", 5);
}

void ChatClient::sendLeaveMultiSlots(std::string multi_ip) {
    Json::FastWriter wr;
    Json::Value send_msg_json;
    send_msg_json["type"] = "m03";
    send_msg_json["multi_ip_addr"] = multi_ip;
    send_msg_ = wr.write(send_msg_json);
    write(pipe_write_, "leave", 6);
}

int ChatClient::checkConnState() {
    if (createSocket() == -1) {
        return 0;
    }
    if (createPipe() == -1) {
        return 0;
    }
    return 1;
}


int ChatClient::run() {

    if (max_fd_ < conn_socket_) {
        max_fd_ = conn_socket_;
    }
    if (max_fd_ < pipe_read_) {
        max_fd_ = pipe_read_;
    }
    max_fd_ += 1;

    while (true) {
        FD_SET(conn_socket_, &read_socket_set_);
        FD_SET(pipe_read_, &read_socket_set_);
        select(max_fd_, &read_socket_set_, NULL, NULL, NULL);

        if (FD_ISSET(conn_socket_, &read_socket_set_)) {
            int read_bytes = read(conn_socket_, recv_msg_, MAX_RECV_LINE);
            Json::Reader reader;
            Json::Value recv_msg_json;
            std::string resp_type;
            if (reader.parse(std::string(recv_msg_), recv_msg_json)) {
                if (recv_msg_json.isMember("type") && recv_msg_json["type"].isString()) {
                    resp_type = recv_msg_json["type"].asString();
                    if (resp_type == "r00" || resp_type == "r02") {
                        std::string source_ip = recv_msg_json["ip"].asString();
                        std::string source_msg = recv_msg_json["msg"].asString();
                        global_ip2msg_mutex.lock();
                        global_ip2msg[source_ip].push_back(source_msg);
                        global_ip2msg_mutex.unlock();
                    }
                    else if (resp_type == "r01") {
                        Json::Value msg_array = recv_msg_json["msg"];
                        std::map<std::string, std::vector<std::string> > ip2msg_vec;
                        std::string temp_ip;
                        global_ip2msg_mutex.lock();
                        for (auto iter = msg_array.begin(); iter != msg_array.end(); ++ iter) {
                            temp_ip = (*iter)["ip"].asString();
                            ip2msg_vec[temp_ip].push_back((*iter)["msg"].asString());
                            global_ip2msg[temp_ip].push_back((*iter)["msg"].asString());
                        }
                        global_ip2msg_mutex.unlock();
                    }
                    else if (resp_type == "r04") {

                        std::string multi_ip = recv_msg_json["multi_ip_addr"].asString();
                        std::string msg = recv_msg_json["msg"].asString();
                        std::string source_ip = recv_msg_json["ip"].asString();
                        //std::cout << multi_ip << " : " << source_ip << " : " << msg << std::endl;
                        global_multi_ip2msg_mutex.lock();
                        global_multi_ip2msg[multi_ip][source_ip].push_back(msg);
                        std::cout << global_multi_ip2msg.size() << std::endl;
                        global_multi_ip2msg_mutex.unlock();
                    }
                }
            }

        }

        if (FD_ISSET(pipe_read_, &read_socket_set_)) {
            int read_bytes = read(pipe_read_, recv_msg_, MAX_RECV_LINE);
            write(conn_socket_, send_msg_.c_str(), strlen(send_msg_.c_str()) + 1);
        }
    }
}

